# Visualización de datos geográficos con leaflet

En esta sesión aprenderemos a utilizar leaflet (opens new window) en nuestros notebooks de python. Es posible también integrar esta librería en R, pero hoy nos limitaremos a python.

La librería que nos ayudará a enlazar python y leaflet será folium, que como veremos es muy cómoda de utilizar.

# Configuración

En primer lugar, actualizaremos folium a la última versión, para conseguir todas las funcionalidades.

!pip install folium==0.12.0

# Visualización de mapas con folium (leaflet)

Importamos las dependencias

import folium
import json

Comenzamos creando un mapa muy simple con un marcador en las coordenadas [40.4066853,-3.7091432]. El parámetro popup permite mostrar información cuando se hace click encima del marcador en el mapa.

myloc = [40.4066853,-3.7091432]
m = folium.Map(location = myloc, zoom_start=15)
folium.Marker(myloc, popup='Estás aquí').add_to(m)

m
Make this Notebook Trusted to load map: File -> Trust Notebook

De hecho, popup admite texto con etiquetas <HTML/>

m = folium.Map(location = myloc, zoom_start=15)
folium.Marker(myloc, popup='<p>Tu IP dice <h4>estás aquí<h4/><p/>').add_to(m)

m
Make this Notebook Trusted to load map: File -> Trust Notebook

Podemos añadir tantos marcadores como necesitemos y cambiar otras propiedades.

folium.Marker(location=[40.42,-3.72], tooltip='pero en realidad estás aquí').add_to(m)
m
Make this Notebook Trusted to load map: File -> Trust Notebook

Ahora descargaremos el mapa de países de europa en formato GeoJson. Podemos configurar nuestro propio mapa en este sitio: https://geojson-maps.ash.ms/

!cd data/ && wget 'https://raw.githubusercontent.com/jlaria/bigdata5/main/data/custom.geo.json'

Con folium.GeoJson podemos mostrar directamente información de un archivo en formato .geo.json.

m = folium.Map()
folium.GeoJson('data/custom.geo.json').add_to(m)
m
Make this Notebook Trusted to load map: File -> Trust Notebook

Podemos seguir configurando nuestro mapa.

m = folium.Map()
folium.GeoJson('data/custom.geo.json',
               style_function = lambda x: {'fillOpacity': '0', 'weight': '1'}).add_to(m)
m
Make this Notebook Trusted to load map: File -> Trust Notebook

Para comprender la estructura de custom.geo.json vamos a traerlo a python.

countries = json.load(open('data/custom.geo.json'))
countries.keys()
countries['type']
countries['features'][0]

Vemos que el campo properties tiene mucha información relacionada con el país, y podemos añadir nuestra propia información. Vamos a utilizar esta información para mostrar un tooltip sobre cada país. Para mostrar colores podemos escoger un tema aquí (opens new window).

m = folium.Map()

colors = ['#8c510a', '#bf812d', '#dfc27d', '#f6e8c3', '#f5f5f5', '#c7eae5', '#80cdc1', '#35978f', '#01665e']

folium.GeoJson('data/custom.geo.json',
               style_function = lambda x: {
                   'fillColor': colors[int(x['properties']['mapcolor9'])-1],
                   'fillOpacity': '0.8',
                   'weight': '1'},
               tooltip = folium.GeoJsonTooltip(
                   fields = ['admin', 'formal_en', 'income_grp']
               )
               ).add_to(m)
m
Make this Notebook Trusted to load map: File -> Trust Notebook

También podemos asignar los colores en función de una variable continua, por ejemplo, gdp_md_est. Para esto, primeramente vamos a explorar el rango de esta variable, en un data frame de pandas.

import pandas as pd

pdf = None 
for i in range(len(countries['features'])):
  pdf = pd.DataFrame(countries['features'][i]['properties'], index=[i]).append(pdf)

pdf
pdf[['admin', 'gdp_md_est']].sort_values('gdp_md_est')

Creamos una escala lineal desde 0 hasta 3

import branca.colormap as cmp
linear = cmp.LinearColormap(
    ['red', 'yellow', 'green'],
    vmin=0, vmax=3,
    caption='GDP (millones)' #Caption for Color scale or Legend
)
linear

03

m = folium.Map()

folium.GeoJson('data/custom.geo.json',
               style_function = lambda x: {
                   'fillColor': linear(x['properties']['gdp_md_est']/1e+6),
                   'fillOpacity': '0.8',
                   'weight': '1'},
               tooltip = folium.GeoJsonTooltip(
                   fields = ['admin', 'formal_en', 'income_grp']
               )
               ).add_to(m)
linear.add_to(m)
m
Make this Notebook Trusted to load map: File -> Trust Notebook

Ahora vamos a escalar por el tamaño de la población.

pdf.loc[:,'gdp_per_capita'] = pdf.gdp_md_est/pdf.pop_est
pdf[['admin', 'gdp_md_est', 'pop_est', 'gdp_per_capita']].sort_values('gdp_per_capita')
admin gdp_md_est pop_est gdp_per_capita
35 Moldova 10670.0 4320748 0.002469
25 Kosovo 5352.0 1804838 0.002965
3 Albania 21810.0 3639453 0.005993
7 Bosnia and Herzegovina 29700.0 4613414 0.006438
49 Ukraine 339800.0 45700395 0.007435
33 Macedonia 18780.0 2066718 0.009087
38 Montenegro 6816.0 672180 0.010140
45 Republic of Serbia 80340.0 7379339 0.010887
8 Belarus 114100.0 9648533 0.011826
41 Romania 271400.0 22215421 0.012217
0 Bulgaria 93750.0 7204687 0.013012
36 Russia 2266000.0 140041247 0.016181
39 Poland 667900.0 38482919 0.017356
31 Latvia 38860.0 2231503 0.017414
29 Lithuania 63330.0 3555179 0.017813
20 Croatia 82390.0 4489409 0.018352
43 Portugal 208627.0 10707924 0.019483
22 Hungary 196600.0 9905596 0.019847
12 Faroe Islands 1000.0 48856 0.020468
13 Estonia 27410.0 1299371 0.021095
40 Slovakia 119500.0 5463046 0.021874
34 Malta 9962.0 405165 0.024588
5 Czech Republic 265200.0 10211904 0.025970
46 Slovenia 59340.0 2005692 0.029586
32 Monaco 976.3 32965 0.029616
28 Italy 1823000.0 58126212 0.031363
18 United Kingdom 1977704.0 62262000 0.031764
19 Greece 343000.0 10737428 0.031944
17 France 2128000.0 64057792 0.033220
16 Spain 1403000.0 40525002 0.034621
10 Germany 2918000.0 82329758 0.035443
23 Isle of Man 2719.0 76512 0.035537
15 Finland 193500.0 5250275 0.036855
11 Denmark 203600.0 5500510 0.037015
4 Belgium 389300.0 10414336 0.037381
47 Sweden 344300.0 9059651 0.038004
14 Guernsey 2742.0 68633 0.039952
1 Austria 329500.0 8210281 0.040133
37 Netherlands 672000.0 16715999 0.040201
27 Iceland 12710.0 306694 0.041442
9 Switzerland 316700.0 7604467 0.041647
2 Andorra 3660.0 83888 0.043630
21 Ireland 188400.0 4203200 0.044823
44 San Marino 1662.0 30324 0.054808
26 Jersey 5100.0 91626 0.055661
6 Aland 1563.0 27153 0.057563
42 Norway 276400.0 4676305 0.059106
30 Luxembourg 39370.0 491775 0.080057
24 Liechtenstein 4160.0 34761 0.119674
48 Vatican 355.0 832 0.426683
for i in range(len(countries['features'])):
  gdp = countries['features'][i]['properties']['gdp_md_est']
  pop = countries['features'][i]['properties']['pop_est']
  countries['features'][i]['properties']['gdp_per_capita'] = gdp/pop
# countries['features'][0]['properties']
linear = cmp.LinearColormap(
    ['red', 'yellow', 'green'],
    vmin=0, vmax=0.1,
    caption='GDP (scaled)' #Caption for Color scale or Legend
)

m = folium.Map()

folium.GeoJson(countries,
               style_function = lambda x: {
                   'fillColor': linear(x['properties']['gdp_per_capita']),
                   'fillOpacity': '0.8',
                   'weight': '1'},
               tooltip = folium.GeoJsonTooltip(
                   fields = ['admin', 'formal_en', 'income_grp', 'gdp_per_capita']
               )
               ).add_to(m)
linear.add_to(m)
m

Make this Notebook Trusted to load map: File -> Trust Notebook

# Ejercicio

La tabla consumption.csv contiene la información del consumo eléctrico de varios países europeos. ¿Serías capaz de mostrar esta información en un mapa sobre los países, con una escala de colores que haga referencia al consumo anual de cada país?